Skip to content

HTML5 高级 API 面试题全解析

一、核心要点速览

💡 核心考点

  • Web Workers: 多线程编程,后台处理耗时任务
  • Geolocation: 地理定位 API 及使用
  • Drag & Drop: 拖放功能实现
  • History API: 单页应用路由基础
  • 其他 API: Page Visibility、Clipboard 等

二、Web Workers 多线程

1. 基础用法

javascript
// 主线程 (main.js)
const worker = new Worker('worker.js')

// 发送数据给 worker
worker.postMessage({ number: 1000000 })

// 接收 worker 的消息
worker.onmessage = (e) => {
  console.log('计算结果:', e.data)
  worker.terminate() // 终止 worker
}

// 错误处理
worker.onerror = (error) => {
  console.error('Worker 错误:', error)
}

// 关闭 worker
// worker.terminate()
javascript
// Worker 线程 (worker.js)
onmessage = (e) => {
  const number = e.data.number
  
  // 执行耗时计算
  const result = heavyComputation(number)
  
  // 返回结果
  postMessage(result)
  
  // 也可以关闭自己
  // close()
}

function heavyComputation(n) {
  let sum = 0
  for (let i = 0; i < n; i++) {
    sum += i
  }
  return sum
}

2. 实际应用场景

javascript
// 场景 1: 大数据处理
const worker = new Worker('process.js')

// 发送大量数据
fetch('/api/large-data')
  .then(res => res.json())
  .then(data => {
    worker.postMessage(data)
  })

worker.onmessage = (e) => {
  console.log('处理完成:', e.data)
  displayResult(e.data)
}

// process.js
onmessage = (e) => {
  const data = e.data
  
  // 复杂的数据处理
  const result = data.map(item => {
    // 耗时操作...
    return transform(item)
  })
  
  postMessage(result)
}
javascript
// 场景 2: 实时计算
// 主线程
const calcWorker = new Worker('calculator.js')

input.addEventListener('input', (e) => {
  const value = e.target.value
  calcWorker.postMessage(value)
})

calcWorker.onmessage = (e) => {
  resultDisplay.textContent = e.data
}

// calculator.js
onmessage = (e) => {
  const value = e.data
  // 复杂计算
  const result = complexCalculation(value)
  postMessage(result)
}

3. 使用限制

┌──────────────────────────────────────────────────────────┐
│              Web Workers 使用限制                         │
└──────────────────────────────────────────────────────────┘

不能做的事:
✗ 访问 DOM 元素
  └─ Worker 没有 window、document 对象

✗ 访问父页面的变量
  └─ 只能通过 postMessage 通信

✗ 某些跨域脚本
  └─ 必须同源或设置 CORS

适合的场景:
✓ 大数据处理(图像处理、文件解析)
✓ 复杂计算(加密解密、数据压缩)
✓ 后台任务(数据同步、心跳检测)
✓ 实时分析(日志分析、指标计算)

不适合的场景:
✗ 简单的异步任务(用 Promise)
✗ 需要 DOM 操作的任务
✗ 频繁通信的任务(通信有开销)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

4. SharedWorker(共享 worker)

javascript
// 主线程
const sharedWorker = new SharedWorker('shared-worker.js')

sharedWorker.port.start()
sharedWorker.port.postMessage('Hello from tab 1')

sharedWorker.port.onmessage = (e) => {
  console.log('收到消息:', e.data)
}

// shared-worker.js
const ports = new Set()

onconnect = (e) => {
  const port = e.ports[0]
  ports.add(port)
  
  port.start()
  
  port.onmessage = (e) => {
    // 广播给所有端口
    ports.forEach(p => {
      if (p !== port) {
        p.postMessage(e.data)
      }
    })
  }
}

三、Geolocation 地理定位

1. 基础用法

javascript
// 获取当前位置
navigator.geolocation.getCurrentPosition(
  // 成功回调
  (position) => {
    const { latitude, longitude, accuracy } = position.coords
    const { altitude, heading, speed } = position.coords
    
    console.log(`
      纬度:${latitude}
      经度:${longitude}
      精度:${accuracy}米
      海拔:${altitude}米
      方向:${heading}度
      速度:${speed}m/s
    `)
    
    // 在地图上标记位置
    showOnMap(latitude, longitude)
  },
  
  // 错误回调
  (error) => {
    switch(error.code) {
      case error.PERMISSION_DENIED:
        console.error('用户拒绝授权')
        break
      case error.POSITION_UNAVAILABLE:
        console.error('位置信息不可用')
        break
      case error.TIMEOUT:
        console.error('获取超时')
        break
      default:
        console.error('未知错误')
    }
  },
  
  // 选项
  {
    enableHighAccuracy: true,  // 高精度模式
    timeout: 5000,             // 超时 5 秒
    maximumAge: 0              // 不使用缓存
  }
)

2. 持续追踪位置

javascript
// 持续追踪(如运动轨迹记录)
const watchId = navigator.geolocation.watchPosition(
  (position) => {
    const { latitude, longitude } = position.coords
    
    // 更新地图上的位置
    updatePosition(latitude, longitude)
    
    // 记录轨迹
    trackPoints.push({
      lat: latitude,
      lng: longitude,
      time: Date.now()
    })
  },
  
  (error) => {
    console.error('定位失败:', error)
  },
  
  {
    enableHighAccuracy: true,
    timeout: 10000,
    maximumAge: 1000  // 1 秒内的缓存可用
  }
)

// 停止追踪
function stopTracking() {
  navigator.geolocation.clearWatch(watchId)
}

3. 在地图上使用

javascript
// 结合百度地图/高德地图
navigator.geolocation.getCurrentPosition((position) => {
  const { latitude, longitude } = position.coords
  
  // 百度地图
  const map = new BMap.Map('container')
  const point = new BMap.Point(longitude, latitude)
  map.centerAndZoom(point, 15)
  
  // 添加标记
  const marker = new BMap.Marker(point)
  map.addOverlay(marker)
  
  // 高德地图
  const amap = new AMap.Map('container', {
    center: [longitude, latitude],
    zoom: 15
  })
  
  const amarker = new AMap.Marker({
    position: [longitude, latitude]
  })
  amap.add(amarker)
})

四、Drag & Drop 拖放 API

1. 基础拖放

html
<div draggable="true" id="dragItem">可拖动物体</div>
<div id="dropZone">放置区域</div>

<style>
#dragItem {
  width: 100px;
  height: 100px;
  background: blue;
  color: white;
  cursor: move;
}

#dropZone {
  width: 200px;
  height: 200px;
  border: 2px dashed #ccc;
  margin-top: 20px;
}

#dropZone.dragover {
  background: #f0f0f0;
}
</style>
javascript
const dragItem = document.getElementById('dragItem')
const dropZone = document.getElementById('dropZone')

// 拖拽元素事件
dragItem.addEventListener('dragstart', (e) => {
  // 设置拖拽数据
  e.dataTransfer.setData('text/plain', e.target.id)
  e.dataTransfer.effectAllowed = 'move'
  
  // 自定义拖拽图像
  // e.dataTransfer.setDragImage(image, x, y)
})

dragItem.addEventListener('dragend', (e) => {
  console.log('拖拽结束')
  e.target.style.opacity = '1'
})

// 放置区域事件
dropZone.addEventListener('dragenter', (e) => {
  e.preventDefault()
  dropZone.classList.add('dragover')
})

dropZone.addEventListener('dragover', (e) => {
  e.preventDefault()  // 必须调用才能放置
  e.dataTransfer.dropEffect = 'move'
})

dropZone.addEventListener('dragleave', () => {
  dropZone.classList.remove('dragover')
})

dropZone.addEventListener('drop', (e) => {
  e.preventDefault()
  dropZone.classList.remove('dragover')
  
  // 获取拖拽数据
  const id = e.dataTransfer.getData('text/plain')
  const draggable = document.getElementById(id)
  
  // 将元素添加到放置区域
  dropZone.appendChild(draggable)
})

2. 拖放事件流程

时间 →  ─────────────────────────────────────────────────►

完整拖放流程:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
用户按下元素


┌─────────────┐
│ dragstart   │ ← 开始拖拽
│ 设置数据     │
└──────┬──────┘


┌─────────────┐
│ drag        │ ← 持续触发(拖动中)
└──────┬──────┘


┌─────────────┐
│ dragenter   │ ← 进入目标区域
└──────┬──────┘


┌─────────────┐
│ dragover    │ ← 在目标区域移动
│ e.preventDefault()│
└──────┬──────┘


┌─────────────┐
│ dragleave   │ ← 离开目标区域
└──────┬──────┘


┌─────────────┐
│ drop        │ ← 释放鼠标
│ 获取数据     │
└──────┬──────┘


┌─────────────┐
│ dragend     │ ← 拖拽结束
└─────────────┘

事件触发顺序:
dragstart → drag → dragenter → dragover → 
(dragleave) → drop → dragend
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

3. 文件拖放上传

javascript
const dropZone = document.getElementById('dropZone')

dropZone.addEventListener('drop', (e) => {
  e.preventDefault()
  
  const files = e.dataTransfer.files
  
  // 处理文件
  Array.from(files).forEach(file => {
    console.log('文件:', file.name, file.size, file.type)
    
    // 上传图片
    if (file.type.startsWith('image/')) {
      uploadFile(file)
    }
  })
})

function uploadFile(file) {
  const formData = new FormData()
  formData.append('file', file)
  
  fetch('/upload', {
    method: 'POST',
    body: formData
  })
  .then(res => res.json())
  .then(data => {
    console.log('上传成功:', data)
  })
}

五、History API 历史管理

1. 基础用法

javascript
// 添加历史记录(不刷新页面)
history.pushState({ page: 1, title: '第一页' }, '第一页', '?page=1')

// 替换当前历史记录
history.replaceState({ page: 2 }, '第二页', '?page=2')

// 监听后退/前进按钮
window.addEventListener('popstate', (e) => {
  console.log('状态:', e.state)
  
  if (e.state) {
    // 根据 state 渲染对应页面
    renderPage(e.state.page)
  }
})

// 导航
history.back()      // 后退一页
history.forward()   // 前进一页
history.go(-2)      // 后退 2 页
history.go(2)       // 前进 2 页

2. 单页应用路由示例

javascript
class SimpleRouter {
  constructor() {
    this.routes = {}
    
    window.addEventListener('popstate', (e) => {
      this.loadRoute(location.pathname)
    })
  }
  
  // 注册路由
  addRoute(path, handler) {
    this.routes[path] = handler
  }
  
  // 导航到指定路径
  navigate(path, state = {}) {
    history.pushState(state, '', path)
    this.loadRoute(path)
  }
  
  // 加载路由
  loadRoute(path) {
    const handler = this.routes[path]
    if (handler) {
      handler()
    } else {
      console.error('404 Not Found')
    }
  }
}

// 使用示例
const router = new SimpleRouter()

router.addRoute('/', () => {
  document.title = '首页'
  document.querySelector('#app').innerHTML = '<h1>首页</h1>'
})

router.addRoute('/about', () => {
  document.title = '关于'
  document.querySelector('#app').innerHTML = '<h1>关于我们</h1>'
})

router.addRoute('/contact', () => {
  document.title = '联系'
  document.querySelector('#app').innerHTML = '<h1>联系方式</h1>'
})

// 初始加载
router.loadRoute(location.pathname)

// 导航
// router.navigate('/about')

六、其他重要 API

1. Page Visibility API 页面可见性

javascript
// 监听页面可见性变化
document.addEventListener('visibilitychange', () => {
  if (document.hidden) {
    // 页面隐藏(切换到其他标签或最小化)
    console.log('页面隐藏')
    
    // 暂停视频播放
    video.pause()
    
    // 停止动画
    cancelAnimationFrame(animationId)
    
    // 减少轮询频率
    clearInterval(pollTimer)
  } else {
    // 页面可见
    console.log('页面可见')
    
    // 恢复播放
    video.play()
    
    // 恢复动画
    animationId = requestAnimationFrame(animate)
    
    // 恢复轮询
    pollTimer = setInterval(poll, 5000)
  }
})

// 检查当前状态
console.log(document.visibilityState)
// 'visible' | 'hidden' | 'prerender'

2. Clipboard API 剪贴板

javascript
// 复制文本
async function copyText(text) {
  try {
    await navigator.clipboard.writeText(text)
    console.log('复制成功')
    showToast('复制成功')
  } catch (err) {
    console.error('复制失败:', err)
    // 降级方案
    fallbackCopy(text)
  }
}

// 粘贴文本
async function pasteText() {
  try {
    const text = await navigator.clipboard.readText()
    console.log('粘贴内容:', text)
    return text
  } catch (err) {
    console.error('粘贴失败:', err)
  }
}

// 复制富文本
async function copyHtml(html, text) {
  const clipboardItem = new ClipboardItem({
    'text/html': new Blob([html], { type: 'text/html' }),
    'text/plain': new Blob([text], { type: 'text/plain' })
  })
  
  await navigator.clipboard.write([clipboardItem])
}

// 降级方案(老浏览器)
function fallbackCopy(text) {
  const textarea = document.createElement('textarea')
  textarea.value = text
  textarea.style.position = 'fixed'
  textarea.style.opacity = '0'
  document.body.appendChild(textarea)
  textarea.select()
  
  try {
    document.execCommand('copy')
    console.log('复制成功(降级方案)')
  } catch (err) {
    console.error('复制失败')
  }
  
  document.body.removeChild(textarea)
}

3. Fullscreen API 全屏

javascript
const element = document.getElementById('video')

// 进入全屏
async function enterFullscreen() {
  try {
    await element.requestFullscreen()
  } catch (err) {
    console.error('全屏失败:', err)
  }
}

// 退出全屏
function exitFullscreen() {
  if (document.fullscreenElement) {
    document.exitFullscreen()
  }
}

// 监听全屏变化
document.addEventListener('fullscreenchange', () => {
  if (document.fullscreenElement) {
    console.log('已进入全屏')
  } else {
    console.log('已退出全屏')
  }
})

// 检查是否支持
if (document.documentElement.requestFullscreen) {
  // 支持全屏
  showFullscreenButton()
}

七、面试标准回答

HTML5 提供了众多强大的 API 来增强 Web 应用能力

Web Workers 允许 JavaScript 在后台线程运行,避免耗时操作阻塞主线程。适用于大数据处理、复杂计算等场景。但 Worker 不能访问 DOM,只能通过 postMessage 与主线程通信。

Geolocation API 提供地理定位功能,可以获取用户的经纬度、海拔、速度等信息。常用于地图应用、位置服务、运动追踪等场景。需要注意用户授权和隐私保护。

Drag & Drop API 实现元素的拖放功能。通过 dragstart、dragover、drop 等事件,可以实现文件上传、元素排序、拖放交互等功能。注意 dragover 事件必须调用 preventDefault 才能放置。

History API 包括 pushState、replaceState 和 popstate 事件,是单页应用路由的基础。可以在不刷新页面的情况下修改 URL 和管理历史记录。

其他实用 API 还包括:Page Visibility 监听页面可见性,用于优化性能;Clipboard API 操作剪贴板;Fullscreen API 控制全屏等。

实际项目中,我经常使用这些 API 来提升用户体验,比如用 Web Workers 处理大数据,用 Geolocation 实现位置服务,用 History API 构建 SPA 路由等。


八、记忆口诀

HTML5 API 歌诀:

Workers 多线程,
后台计算不卡顿。
Geolocation 来定位,
地图服务离不开。

Drag Drop 能拖放,
文件上传很方便。
History 管路由,
单页应用它做主。

Visibility 看可见,
性能优化靠它行。
Clipboard 复制粘,
Fullscreen 全屏现!

九、推荐资源


十、总结一句话

  • Web Workers: 多线程 + 后台计算 = 不阻塞主线程 ⚙️
  • Geolocation: 地理定位 + 地图服务 = LBS 应用基础 📍
  • Drag & Drop: 拖拽交互 + 文件上传 = 更好的用户体验 🖱️
  • History API: 路由管理 + 单页应用 = SPA 核心技术 🔄
  • Page Visibility: 可见检测 + 性能优化 = 智能资源管理 👁️
最近更新